mynote-front
mynote-front coninuous build
mynote front continuous build
lv1= lv2= type=
mynote front 部署
E:\xunwu\projects\官网\xunwu\README.md
nuxt <[--
问题:使用 nuxt start,至少要 npm install nuxt 这个很大、很多文件
--]>
nodejs linux 安装
node-sass
npm config
cd --front--install-path--
npm config set registry https://registry.npm.taobao.org
npm config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/
npm install --user=0
npx nuxt build
npm install -g pm2
不用pm2,启动(production mode)命令为 npx nuxt start,因此,pm2 启动为(-- 后面的参数会传递给 npx 命令):
pm2 start npx -- nuxt start
pm2 delete npx
最后copy favicon
linux 脚本 汇总
# 上传 node 安装包、front git 压缩包 到 /root/init
cd /root/init
# 解压 front
# 修改 my.js 配置,注意 baseURL 配置
-- node 安装 nodejs linux 安装
cd /home/www/front
npm config set registry https://registry.npm.taobao.org
npm config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/
npm install --user=0
npm install -g pm2
npx nuxt build
pm2 start npx -- nuxt start
# 虚拟内存
cd /usr
mkdir swap
cd swap/
dd if=/dev/zero of=/usr/swap/swapfile bs=1M count=2048
mkswap /usr/swap/swapfile
swapon /usr/swap/swapfile
# 设置开机自动启用虚拟内存,在etc/fstab文件中加入如下命令
# 使用vim编辑器打开/etc/fstab文件
echo "/usr/swap/swapfile swap swap defaults 0 0" >> /etc/fstab
windows
〖E:\uninote\deploy-windows〗
mynote front servers
layout
default.vue
/**
* 在页面加载前先获取 localStorage 中的用户信息
*/
mounted() {
this.$store.dispatch('auth/getUserInfo');
}
<template>
<div class="template-container">
<v-header></v-header>
<nuxt/>
</div>
</template>
index.vue
.editorconfig
detect indent
mynote-front
:ssr时在服务器端执行,浏览器不执行。在用户手动路由时,会执行。
lv1= lv2= type=
图片等比例缩放 scaleImg
align center 居中
SHA-1: 2f1374818427b85c70657c4a47e303fcd64ee308
* [feat]: 首页文章缩略图等比例缩放
naturalWidth naturalHeight
load 事件
__uninote_scaled__ 缓存
mode:fill full
container 需要 relative、abs等 position
组件的mounted updated 都需要监听
问题:
通过 ref 拿到组件,但没法追加监听 mounted/updated ?
lv1= lv2= type=
mynote-front my config nuxt.config.my.js
因为是嵌套结构,所以用这种方式更方便:
// load custom config
var fs = require("fs");
let path = __dirname + '/nuxt.config.my.js';
if (fs.existsSync(path)) {
myconfig = require(path);
myconfig(module.exports);
}
config.axios.baseURL = config.proxy["/api"] = "http://localhost:222/";
---- nuxt.config.my.js for online
// 直接修改默认配置
module.exports = function (config) {
config.axios.baseURL = config.proxy["/api"] = "http://127.0.0.1:85/";
config.build.extend = function (config, ctx) {
config.devtool = 'source-map';
}
config.server.port = 8888;
}
---- nuxt.config.my.js for test
// 直接修改默认配置
module.exports = function (config) {
config.axios.baseURL = config.proxy["/api"] = "http://dev.rongyipiao.com/";
config.build.extend = function (config, ctx) {
config.devtool = 'none';
}
config.server.port = 80;
}
---- for test in one server
// 直接修改默认配置
module.exports = function (config) {
config.proxy["/api"] = "http://127.0.0.1:85/";
config.axios.baseURL = config.proxy["/api"] = "http://127.0.0.1:85";
config.build.extend = function (config, ctx) {
config.devtool = 'none';
}
config.server.port = 80;
}
---- for test local
// 直接修改默认配置
module.exports = function (config) {
config.axios.baseURL = config.proxy["/api"] = "http://192.168.0.121/";
config.build.extend = function (config, ctx) {
config.devtool = 'source-map';
}
config.server.port = 3333;
}
mynote front design
mynote design
lv1= lv2= type=
mynote front element-ui
Nuxt中ElementUI的使用
https://www.cnblogs.com/shenyf/p/8361049.html
https://blog.csdn.net/Calla_Lj/article/details/86592491
nuxt.config.js
css: [
'element-ui/lib/theme-chalk/index.css',
'~/assets/stylus/main.styl'
],
assets/stylus/variable.styl 全局公共变量
element-ui 主题
定制主题 theme
assets/element-variables.scss element ui 主题修改
c1ecf1c94d7881e2ea8fc0472d7bbc89dc74574b
lv1= lv2= type=
form 表单验证 ----
单一验证,全部验证,部分验证,返回 promise
form 表单验证 ----
nick name
/**
* 验证用户名合法性
*/
validateNickname(cb) {
return this.$refs['ruleForm'].validateField("nickname", (errMsg) => {
login
async login() {
this.$refs['ruleFormRef'].validate(async valid => {
if (valid) {
register
// 此时不验证图形验证码
let p = elformValidate(this.$refs["ruleFormRef"], ['nick', 'tel', 'tel_code', 'password']);
elformValidate
/**
* 封装 el-form 的验证,返回 promise
*/
export const elformValidate = (form, fields) => {
lv1= lv2= type=
mynote front kbp
到后台服务器的网络请求监控
http.js:
function request(url, options, cb) {
return new ClientRequest(url, options, cb);
}
E:\uninote\mynote-front\node_modules\@nuxt\server\dist\server.js
const nuxtMiddleware = ({ options, nuxt, renderRoute, resources }) => async function nuxtMiddleware(req, res, next) {
// Get context
const context = utils.getContext(req, res);
const url = decodeURI(req.url);
res.statusCode = 200;
try {
const result = await renderRoute(url, context);
await nuxt.callHook('render:route', url, result, context);
/**
* Dispatch a request
*
* @param {Object} config The config specific for this request (merged with this.defaults)
*/
Axios.prototype.request = function request(config) {
/*eslint no-param-reassign:0*/
// Allow for axios('example/url'[, config]) a la fetch API
if (typeof config === 'string') {
config = utils.merge({
url: arguments[0]
}, arguments[1]);
}
config = utils.merge(defaults, {method: 'get'}, this.defaults, config);
net.js:
function connect(...args) {
var normalized = normalizeArgs(args);
var options = normalized[0];
debug('createConnection', normalized);
var socket = new Socket(options);
if (options.timeout) {
socket.setTimeout(options.timeout);
}
return socket.connect(normalized);
}
ssr时
E:\uninote\mynote-front-test\node_modules\follow-redirects\index.js
assert.equal(options.protocol, protocol, "protocol mismatch");
debug("options", options);
return new RedirectableRequest(options, callback);
};
E:\uninote\mynote-front\node_modules\follow-redirects\index.js
// Create the native request
var request = this._currentRequest =
nativeProtocol.request(this._options, this._onNativeResponse);
console.log(this._options);
this._currentUrl = url.format(this._options);
E:\uninote\mynote-front\node_modules\axios\lib\core\Axios.js
Axios.prototype.request = function request(config) {
/*eslint no-param-reassign:0*/
// Allow for axios('example/url'[, config]) a la fetch API
if (typeof config === 'string') {
config = utils.merge({
url: arguments[0]
}, arguments[1]);
}
非ssr时
E:\uninote\mynote-front-test\node_modules\http-proxy\lib\http-proxy\passes\web-incoming.js
console.log("req:", req.hostname, req.path, "--->", options.hostname);
var proxyReq = (options.target.protocol === 'https:' ? https : http).request(
common.setupOutgoing(options.ssl || {}, options, req)
);
lv1= lv2= type=
mynote front ssr
mynote front kbp
nuxt ssr
E:\uninote\mynote-front-test\node_modules\@nuxtjs\axios\lib\module.js
// Set _AXIOS_BASE_URL_ for dynamic SSR baseURL
process.env._AXIOS_BASE_URL_ = options.baseURL
最终被生成到了这里:
E:\uninote\mynote-front-test\.nuxt\axios.js
export default (ctx, inject) => {
// baseURL
const baseURL = process.browser
? '/'
: (process.env._AXIOS_BASE_URL_ || 'http://192.168.0.121/')
填坑记录
collin 将 ssr 的代理 baseURL 配置删除了,因此 ssr 代理的 base 由默认值决定。部署的 test1 正常:
axios.js 生成为:
// baseURL
const baseURL = process.browser
? '/'
: (process.env._AXIOS_BASE_URL_ || 'http://localhost:80/')
而 test1 front server 正好是在 80 端口,因此此 ssr 代理请求作为普通的请求将再次被代理,此时能正确的拿到结果。
再次部署 test2 就出了问题:
axios.js 生成为(端口变为3000,gogs的端口,原因不得而知):
// baseURL
const baseURL = process.browser
? '/'
: (process.env._AXIOS_BASE_URL_ || 'http://localhost:3000/')
因此代理结果将变为 404。
lv1= lv2= type=
router navigation guard
Navigation Guards
created/mounted 添加 event handler 要注意,(特别是多全局对象添加),因为可能被多次执行,造成多次回调。
本质是声明周期不一致造成的(组件的生命周期 和 $router 的生命周期不一致,后者为全局的)
方法1:
mounted() {
this.$router.afterEach(this.routerHook);
}
beforeDestroy() {
let i = this.$router.afterHooks.indexOf(this.routerHook);
if (i !== -1) {
this.$router.afterHooks.splice(i, 1);
}
},
methods: {
routerHook() {
},
}
SHA-1: 4af32e7677c5e0092b18400b51ec092dc9e0b9e9
* unregister router hook -- beforeDestory 方案
方法2:
watch: {
$route() {}
}
轮播图 盗链 缓存问题
轮播图 不要设置第三方网站的链接,否则其他人访问时可能会出现 403
mounted() {
document.getElementById("dialog-img-box").addEventListener("touchmove", (e) => {
e.stopPropagation();
});
// 监听滚动事件
window.addEventListener('scroll', this.onScroll);
blur 时输入丢失问题
focus 变化导致组件更新,input value 依赖从父组件中传入的 prop,如果此 prop 没有反向更新到父组件,则在更新时 value 数据丢失。
SHA-1: d60b0362fa80b0f3e214f37c68abe602fe117066
* blur ok
input 点击问题;padding problem
E:\uninote\记录视频\fe\padding-problem.mp4
SHA-1: 4f35d65a6734e13f550a62f5a3ae4ced9e9f67d7
* [fix]: input 点击问题
loading 闪烁 问题
禁用loading动画更明显看出来
v-loading:这个会在附属的元素上居中,因此当元素比较高时,就看不到了,而且会随着元素的height而变化位置,不好。
暂时取消 loading 动画,但保留 loading 状态。
SHA-1: 589e3e8668e912b9cf8e0bf1efbd8225607e6d74
* [chg]: loading 优化:避免无结果的闪烁;取消 loading 动画,但保留 loading 状态(通过顶部进度条指示 loading)。
590a27a3d84d3dc163749a1d6218df03292448f9..589e3e8668e912b9cf8e0bf1efbd8225607e6d74
lv1= lv2= type=
npx 启动问题
sf.sh & sfp.sh
一台机器上build的结果,在另一台机器上 npx nuxt start 不行?原因未知。用这个:
node node_modules/nuxt/bin/nuxt.js start
pm2 则改为:
pm2 start node -- node_modules/nuxt/bin/nuxt.js start
-- 共三种启动方式
lv1= lv2= type=
搜索
es 搜索 api
focus 时全选
快捷键搜索
更多判定:不能根据total 判定,因为存在 es 中的结果,没有 mysql 对应数据的问题。实际展示结果比 es 返回结果少。
最终使用:如果返回的数组长度为0,则认为没有更多了
export const processArticles = (article) => {
// 如果搜出来的文章没有对应的信息(_artinfo === []),则证明是 es 中的垃圾数据,忽略掉即可
lv1= lv2= type=
图片转储
http://uninote.com.cn/book/1071710306/1826
junction __pic E:\uninote\mynote\basic\web\docs\__pic
const scriptjs = process.client ? require('scriptjs') : '';
// Import and Set Nuxt.js options
let config = require('../nuxt.config.js')
config.dev = !(process.env.NODE_ENV === 'production')
![](/__pic/QypilpbC3ns1.png)
![](/__pic/xF4Ur9RY2kiu.png)
http://localhost:3000/__pic/QypilpbC3ns1.png
![](http://localhost:3000/__pic/QypilpbC3ns1.png)
![](http://localhost:3000/__pic/QypilpbC3ns1.png)
![](https://user-gold-cdn.xitu.io/2019/11/11/16e5ad3e233da76a?w=164&h=80&f=png&s=2862)
只会替换一次:
![](http://localhost:3000/__pic/QypilpbC3ns1.png)
![](http://localhost:3000/__pic/QypilpbC3ns1.png)
lv1= lv2= type=
* [opt]: 图片转储优化:尽量使用半绝对路径(不带host,以"/"开头的路径)
SHA-1: 4dc52e5236b8aa4c99238c41b70ccd9384cd7287
lv1= lv2= type=todo
todo:一次性全部替换,但是正则干扰?
需要取当时的 str:
str = str.replace(url, res);
E:\uninote\mynote-online-data\2019-11-10-迁移\docs\1079089832\随笔\maven私服搭建与jar包上传和下载.md
![](http://on.rongyipiao.com//link/take/lib/php/../uploads/foh1ngUI.png)
lv1= lv2= type=
使用 nuxt-link 后重复:
vue.runtime.esm.js:619 [Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>. Bailing hydration and performing full client-side render.
a 标签不能嵌套:
<a href="https://www.google.com" display="block">
<span>google</span>
<div>
<a href="https://www.baidu.com" display="block">baidu</a>
</div>
</a>
确实需要两个 a 标签,可以这样处理:
SHA-1: d1ef591078055b6579cd38698c8eadb2fbed595f
* [chg]: 头像链接到个人主页
使用 absolute + 占位符
lv1= lv2= type=
没有使用 ssr 造成的闪烁问题
E:\uninote\记录视频\fe\ssr-problem.mp4
ssr的内容是不带登录信息的,因此会在用户信息从 localstorage 中加载后变化(闪烁)
lv1= lv2= type=
在 ssr 时就加载登录信息(asyncData)
* [opt]: auth/getUserInfo 改为从接口获取数据,并保证仅调用接口一次;首页使用 ssr 方式加载
lv1= lv2= type=
domEvent scrollLoad 触底加载
lodash
SHA-1: 3a7f43bdd9c1795f75b172cdcc0cd07039d756c9
* opt: 提取 domEvent & scrollLoad
...
SHA-1: c1f94b5aa9f22fd409a07719f7ec9d92db7fa54e
* opt: 首页 loading 优化
在 loading 完成前,多次触底只会触发一次 loading
注意返回 promise(如果需要 loading 控制)
自动取消事件注册
返回 loader,force load,统一 load 入口
1 loading 过滤
2 scroll 高度计算,触底或者 force 才会 throttle,
3 throttle 过滤
lv1= lv2= type=
iconfont
路径 ~
iconfont branch:
a3598c847cf2db3285983724d1e32cfedd27a6ed
4 种方案,第二种最优,下载下来后修改最小
第二种方案优化:
SHA-1: 96f106a460c557649f66e21bd2404c413ca7b439
* min 3
只需要修改一处:
https://uninote.com.cn/book/1027/4321#h-iconfont%202-1
注意
@import 相对于主文件的路径??
styl 改为 css 后缀就不行了,后缀名对 loader 有影响
新增、修改
之前的项目找不到了,只能新增
图标串了:
http://video.dajxyl.com/video_play.html?video_url=http://admin.dajxyl.com/oss?path=video/upload/202203/20220305_211236.mp4
lv1= lv2= type=
login 状态检查,checkNotLogin checkLogin 需要配合 ssr
lv1= lv2= type=
getUserInfo getMyInfo 获取用户信息
this.$store.dispatch('auth/getUserInfo'); 在所有 layout、需要ssr 的地方(asyncData)中调用
不用 ssr,则或导致头像部分闪烁
localStorage 没有使用,仅依赖 php cookie 保持登录状态
lv1= lv2= type=
el-dialog lock-scroll 问题 + html 样式问题
el-dialog
html
overflow: auto;
搜索 message:lock scroll
测试点:
editor 是否正常撑起
注册页面
头像下拉菜单
右键菜单:
http://zentao.uninote.com.cn/zentao/task-view-15.html
http://zentao.uninote.com.cn/zentao/task-view-16.html
http://zentao.uninote.com.cn/zentao/task-view-48.html
el-popup-parent--hidden
close-on-click-modal
html 样式问题研究 2021-7-2
branch:html-style
SHA-1: 540931a220a687d90fbda0e9824d8c1e162dde4f
* html scoped 尝试,通过 xxx 动态样式实现
const html = document.getElementsByTagName('html')[0];
html.setAttribute('style', "height: auto; overflow: hidden");
html 无法使用 scoped 方式局部化处理,可以通过动态设置 xxx 样式实现
http://video.dajxyl.com/video_play.html?video_url=https://admin.dajxyl.com/oss?path=video/upload/202107/20210702_151401.mp4
html样式的影响:
- 自适应高度: height: 100%(编辑、注册等页面)
- dialog lock scroll: overflow: hidden
- dialog 不要滚动到顶部: height: auto (see 重现 dialog 滚动到顶部)
http://video.dajxyl.com/video_play.html?video_url=https://admin.dajxyl.com/oss?path=video/upload/202107/20210702_151605.mp4
html 元素无法实现对 body 的剪裁:
height: 400px;
overflow: hidden;
axios
axios
timeout:
$axios.$post(url, data, {timeout: 1100}
or
$axios.defaults.timeout = 30000; // 默认超时时间
lv1= lv2= type=
mynote front debugger
debugger=1 开启,仅在 default layout 中启动
mounted() {
this.$store.dispatch('auth/getUserInfo');
// eruda debugger, using "?debugger=1" to start and "?debugger=0" to destroy
const DEBUGGER_KEY = 'debugger';
const url = new URL(location.href);
const value = url.searchParams.get(DEBUGGER_KEY);
if (value !== null) {
localStorage.setItem(DEBUGGER_KEY, value);
}
if (localStorage.getItem(DEBUGGER_KEY) === "1") {
const script = document.createElement('script');
script.src = "//cdn.jsdelivr.net/npm/eruda";
document.body.appendChild(script);
script.onload = function () {
eruda.init();
}
}
}